/**
 * This file is part of the CAKIS project.
 * 
 * Copyright (c) 2009-2010 - Florian Arndt, Christian Kerl
 * 
 * @license GNU Lesser General Public License v3 <http://www.opensource.org/licenses/lgpl-3.0.html>
 * @since   11.04.2010
 * @version SVN: $Id: StockServiceImpl.java 156 2010-05-19 14:29:55Z christian-kerl@web.de $
 */
package org.cakis.server.service.impl;

import java.util.List;

import javax.ejb.Stateless;

import org.cakis.server.Names;
import org.cakis.server.model.BaseProduct;
import org.cakis.server.model.Product;
import org.cakis.server.model.ProductListEntry;
import org.cakis.server.model.ProductQuantity;
import org.cakis.server.model.ProductType;
import org.cakis.server.model.StockItem;
import org.cakis.server.model.repository.Range;
import org.cakis.server.model.repository.StockItemRepository;
import org.cakis.server.service.ProductNotFoundException;
import org.cakis.server.service.ProductService;
import org.cakis.server.service.StockService;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.log.Log;

/**
 * StockServiceImpl
 *
 * @author Christian Kerl
 */
@Stateless
@Name(Names.StockService)
@Scope(ScopeType.APPLICATION)
@Startup
public class StockServiceImpl implements StockService.Local {

    @Logger
    private Log log;

    private StockItemRepository stockItemRepository;

    private ProductService productService;

    @In(Names.StockItemRepository)
    public void setStockItemRepository(StockItemRepository stockItemRepository) {
        this.stockItemRepository = stockItemRepository;
    }

    @In(Names.ProductService)
    public void setProductService(ProductService productService) {
        this.productService = productService;
    }

    @Override
    public boolean addStockItem(Long productId, int count) throws ProductNotFoundException {
        Product product = productService.getProduct(productId);

        for (int a = 0; a < count; a++) {
            StockItem item = new StockItem();
            item.setProduct(product);
            item.setQuantity(product.getStandardQuantity());

            stockItemRepository.store(item);
        }

        return true;
    }

    @Override
    public int deleteStockItem(Long productId, int count) throws ProductNotFoundException {
        Product product = productService.getProduct(productId);

        List<StockItem> items = stockItemRepository.findByProduct(product.getId(), new Range(count));

        for(StockItem item : items) {
            stockItemRepository.delete(item);
        }

        return items.size();
    }

    @Override
    public ProductListEntry getMissingNumberOfStockItemsFor(BaseProduct product, ProductQuantity quantity) {
        List<StockItem> items = stockItemRepository.findByProductOrProductType(product.getId());

        if(quantity.getNumberOfPieces() > 0.0f && quantity.getQuantity() > 0.0f) {
            log.warn("Case001: Not implemented!");

            return new ProductListEntry(product, 0);
        }

        Product refProduct = null;

        if(items.isEmpty()) {
            if(product instanceof ProductType) {
                ProductType type = (ProductType) product;
                List<Product> refProducts = type.getProducts();

                if(!refProducts.isEmpty()) {
                    refProduct = refProducts.get(0);
                }
            } else if(product instanceof Product) {
                refProduct = (Product) product;
            } else {
                log.error("Unknown BaseProduct type #0", product.getClass());
                throw new IllegalStateException();
            }

            if(refProduct != null) {
                ProductQuantity empty = new ProductQuantity();
                empty.setNumberOfPieces(0.0f);
                empty.setQuantity(0.0f);

                StockItem dummy = new StockItem();
                dummy.setProduct(refProduct);
                dummy.setQuantity(empty);

                items.add(dummy);
            } else {
                return new ProductListEntry(product, 1);
            }
        } else {
            refProduct = items.get(0).getProduct();
        }

        int number = 0;
        ProductQuantity stdQuantity = refProduct.getStandardQuantity();

        if(quantity.getNumberOfPieces() > 0.0f) {
            float piecesInStock = sumNumberOfPieces(items);

            number = calculateMissingStockItems(
                    quantity.getNumberOfPieces(),
                    piecesInStock,
                    stdQuantity.getNumberOfPieces()
            );
        }

        if(quantity.getQuantity() > 0.0f) {
            log.warn("Case004: Quantity Scaling not implemented!");

            float quantityInStock = sumQuantity(items);

            number = calculateMissingStockItems(
                    quantity.getQuantity(),
                    quantityInStock,
                    stdQuantity.getQuantity()
            );
        }

        return new ProductListEntry(refProduct, number);
    }

    private float sumNumberOfPieces(List<StockItem> items) {
        float result = 0.0f;

        for(StockItem item : items) {
            result += item.getQuantity().getNumberOfPieces();
        }

        return result;
    }

    private float sumQuantity(List<StockItem> items) {
        float result = 0.0f;

        for(StockItem item : items) {
            result += item.getQuantity().getQuantity();
        }

        return result;
    }

    private int calculateMissingStockItems(float required, float inStock, float standard) {
        int result = 0;

        if(inStock < required) {
            double missing = Math.ceil(required - inStock);

            int missingStockItems  = (int) Math.ceil(missing / standard);

            return missingStockItems;
        }

        return result;
    }
}
